package calculator;

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

import java.util.HashMap;
import java.util.Map;

/**
 * antlr:hive sql,spark sql
 * javacc：calcite,flink sql
 * <p>
 * Java
 * 1.词法分析-标记流
 * 2.语法分析-抽象语法树
 * 3.翻译成汇编/直接解释执行
 * <p>
 * sql
 * 1.词法分析-标记流
 * 2.语法分析-抽象语法树
 * 3.语义分析(类型检查)
 * 4.将抽象语法树翻译成执行计划
 * 5.汇编 将执行计划翻译成目标代码(MR /Flink底层API)
 */

//实现计算器
public class Calculator extends CalculatorBaseVisitor<Integer> {
    //key:变量名/标识符  v:值
    Map<String, Integer> memory = new HashMap<>();

    //ID '=' expr NEWLINE
    @Override
    public Integer visitAssign(CalculatorParser.AssignContext ctx) {
        var id = ctx.ID().getText(); // id在'='的左侧
        var value = visit(ctx.expr());  // '='右侧是表达式
        memory.put(id, value);          // 将变量和值的映射关系存储在符号表中
        return value;
    }


    //expr NEWLINE
    @Override
    public Integer visitPrintExpr(CalculatorParser.PrintExprContext ctx) {
        var value = visit(ctx.expr());//对表达式求值
        System.out.println(value);
        return 0;
    }


    //INT
    @Override
    public Integer visitInt(CalculatorParser.IntContext ctx) {
        return Integer.parseInt(ctx.INT().getText());
    }


    //ID
    @Override
    public Integer visitId(CalculatorParser.IdContext ctx) {
        var id = ctx.ID().getText();
        if (memory.containsKey(id)) return memory.get(id);
        return 0;
    }


    //expr op=('*'|'/') expr
    @Override
    public Integer visitMulDiv(CalculatorParser.MulDivContext ctx) {
        var left = visit(ctx.expr(0));
        var right = visit(ctx.expr(1));
        if (ctx.op.getType() == CalculatorParser.MUL) return left * right;
        return left / right;
    }


    //expr op=('+'|'-') expr
    @Override
    public Integer visitAddSub(CalculatorParser.AddSubContext ctx) {
        var left = visit(ctx.expr(0));
        var right = visit(ctx.expr(1));
        if (ctx.op.getType() == CalculatorParser.ADD) return left + right;
        return left - right;
    }

    //'(' expr ')'
    @Override
    public Integer visitParens(CalculatorParser.ParensContext ctx) {
        return visit(ctx.expr());
    }

    public static void main(String[] args) {
        String s = """
                1+2
                a = 1
                b = 2
                a + b
                """;
        //讲字符串转成流
        var stream = CharStreams.fromString(s);
        //实例化词法分析器
        var lexer = new CalculatorLexer(stream);
        //词法分析
        var tokens = new CommonTokenStream(lexer);

        //实例化语法分析器
        var parser = new CalculatorParser(tokens);
        //语法分析并转成抽象语法树
        var tree = parser.prog();
        //实例化计算器
        var calculator = new Calculator();
        calculator.visit(tree);
    }
}
